package com.scs.application.modules.upms.security;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.modules.base.entity.Hospital;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.mapper.HospitalMapper;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.upms.entity.Office;
import com.scs.application.modules.upms.entity.OnlineUser;
import com.scs.application.modules.upms.entity.Role;
import com.scs.application.modules.upms.entity.User;
import com.scs.application.modules.upms.mapper.OfficeMapper;
import com.scs.application.modules.upms.mapper.OnlineUserMapper;
import com.scs.application.modules.upms.mapper.RoleMapper;
import com.scs.application.modules.upms.mapper.UserMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.bouncycastle.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.stream.Collectors;

/**
 * token 鉴权、授权
 */
public class AccessTokenRealm extends AuthorizingRealm {

    public static final String CACHE_NAME = "shiroCache";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OnlineUserMapper onlineUserMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private OfficeMapper officeMapper;

    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private HospitalMapper hospitalMapper;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof AccessToken;
    }

    /**
     * 授权函数
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        final SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        User currentUser = (User) SecurityUtils.getSubject().getPrincipal();

//        List<Role> roles = userService.getUserRoles(currentUser);
//
//        // 添加角色
//        simpleAuthorizationInfo.addRoles(roles.stream().map(role -> role.getRoleCode()).collect(Collectors.toList()));

        // 测试时使用
        simpleAuthorizationInfo.addStringPermission("*");

        // 如果是超级用户，直接加所有的权限
//        if (currentUser.isSuperAdmin()) {
//            simpleAuthorizationInfo.addStringPermission("*");
//        } else {
//            List<Right> userRights = userService.getUserRights(currentUser);
//            userRights.stream().filter(o -> StringUtils.isNotBlank(o.getPermissions())).forEach(o -> {
//                simpleAuthorizationInfo.addStringPermissions(Lists.newArrayList(StringUtils.split(o.getPermissions(), ";")));
//            });
//        }


        return simpleAuthorizationInfo;
    }

    /**
     * 认证函数,登录时调用
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String accessToken = (String) authenticationToken.getPrincipal();

        //根据accessToken，查询用户信息
        OnlineUser token = onlineUserMapper.selectOne(
                Wrappers.<OnlineUser>query()
                        .eq("token", accessToken)
                        .last("limit 1")
        );
        //token失效
        if (token == null || token.getExpireTime().getTime() < System.currentTimeMillis()) {
            throw new ExpiredCredentialsException("token失效，请重新登录");
        }

        //查询用户信息
        User user = userMapper.selectOne(Wrappers.<User>query().eq("login_key", token.getLoginKey())
                .or().eq("login_key", Strings.toUpperCase(token.getLoginKey()))
                .or().eq("login_key", Strings.toLowerCase(token.getLoginKey())));
        if (user == null) {
            throw new UnknownAccountException("未知的帐号信息");
        }

        /**
         * 此处 principal 的值为 {@link User}类型，所以在 {@link AuthorizingRealm#getAuthorizationInfo} 从缓存里面加载信息时，
         * key 为 {@link User} 对象，需重写 {@link User#equals(Object)} 和 {@link User#hashCode()} 方法
         */
        UserPrincipal principal = new UserPrincipal();
        BeanUtils.copyProperties(user, principal);

        JSONArray rolesId = user.getRolesId();
        List<Role> roles = rolesId == null ? Lists.newArrayList() : roleMapper.selectList(new QueryWrapper<Role>().eq("id", user.getRolesId().toJavaList(String.class)));
        principal.setRoleCodes(roles.stream().map(o -> o.getCode()).collect(Collectors.toList()));

        //查询部门信息
        Office office = officeMapper.selectById(user.getOfficeId());
        if(office != null) {
            principal.setOfficeId(office.getId());
            principal.setOfficeCode(office.getCode());
            principal.setOfficeName(office.getName());
        }

        Supplier supplier = supplierMapper.selectOne(Wrappers.<Supplier>query().eq("office_id", principal.getOfficeId()).or().eq("login_key", principal.getLoginKey()));

        if (supplier != null) {
            principal.setSupplier(supplier);
        }
        Hospital hospital = hospitalMapper.selectOne(Wrappers.<Hospital>query().eq("office_id", principal.getOfficeId()));
        if (hospital != null) {
            principal.setHospital(hospital);
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, accessToken, getName());
        return info;
    }


    @Override
    public String getName() {
        return super.getName();
    }
}
